// Package c2 提供HTTP请求和响应处理功能，支持GET、POST等多种请求方式，包含请求构建、响应解析、结果校验等特性。
//
// 主要功能：
//
//  1. 支持多种HTTP请求方法
//  2. 支持请求参数、请求头、请求体的设置
//  3. 支持JSON、Form、Text等多种请求体格式
//  4. 支持文件上传
//  5. 提供丰富的响应处理功能
//  6. 支持全局配置管理
package c2

import (
	"encoding/json"
	"fmt"
	"log"
	"reflect"
	"sort"
	"strconv"
	"strings"

	"gitee.com/tuboyou/c2/u2"
)

// inner_config 表示内部配置结构体
//
// 字段说明：
//
//	xfrom - 内置来源标识
//	resultPath - 结果保存路径
//	retry - 重试次数，最大10次
//	showDebug - 是否显示debug信息
//	globalHeaders - 全局请求头
type inner_config struct {
	xfrom                 string            // 内置来源标识
	resultPath            string            // 结果保存路径
	retry                 int               // 重试次数,最大10次
	showDebug             bool              // 是否显示debug信息
	globalHeaders         map[string]string // 全局header
	getOrPost             bool              //true:post else get
	getOrPostBodyPosition int               // 0:params 1:params2 kv body  2:params3 json body
}

var iconf *inner_config

func init() {

	iconf = &inner_config{xfrom: "interfacetest", globalHeaders: make(map[string]string)}
	if iconf.showDebug {
		log.Println("初始化成功")
	}
}

// SetGetOrPost2Post 设置post请求
// 参数：
//
//	position - 0:params 1:params2 kv body  2:params3 json body
func SetGetOrPost2Post(position int) {
	iconf.getOrPost = true
	iconf.getOrPostBodyPosition = position
	if iconf.showDebug {
		log.Println("设置post请求")
	}
}

// SetXfrom 设置来源标识，在header中添加xfrom
//
// 参数：
//
//	xfrom - 来源标识字符串
//
// 注意：
//
//  1. 默认值为"interfacetest"
//  2. 如果启用了调试模式，会打印设置日志
func SetXfrom(xfrom string) {
	iconf.xfrom = xfrom
	if iconf.showDebug {
		log.Println("设置来源标识：", xfrom)
	}
}

// SetResultPath 设置结果保存路径
//
// 参数：
//
//	p - 文件路径
//	isRemoveOld - 是否立即删除原有文件
//
// 注意：
//
//  1. 如果isRemoveOld为true，会立即删除指定路径的文件
//  2. 如果启用了调试模式，会打印设置日志
func SetResultPath(p string, isRemoveOld bool) {
	if isRemoveOld {
		u2.RemoveFile(p)
		if iconf.showDebug {
			log.Println("删除原有文件：", p)
		}
	}
	iconf.resultPath = p
	if iconf.showDebug {
		log.Println("设置结果保存路径：", p)
	}
}

// SetGlobalHeader 设置全局请求头
//
// 参数：
//
//	name - 头名称
//	value - 头值
func SetGlobalHeader(name, value string) {
	if iconf.globalHeaders == nil {
		iconf.globalHeaders = make(map[string]string)
	}
	iconf.globalHeaders[name] = value
}

// printJson 递归打印JSON格式的数据
//
// 参数：
//
//	v - 要打印的任意类型数据
//	kong - 当前缩进字符串
//	stru - 结构体定义字符串
//	isadd - 是否添加结构体定义
//	showjson - 是否打印JSON内容
//	showResult - 是否在结构体定义中添加结果校验标签
//
// 返回值：
//
//	string - 生成的结构体定义字符串
//
// 注意：
//
//  1. 支持string、int、float64、bool、[]interface{}、map[string]interface{}等类型
//  2. 对于map[string]interface{}类型，会按key排序后打印
//  3. 对于嵌套结构，会自动增加缩进
//  4. 当isadd为true时，会生成对应的Go结构体定义
//  5. 当showResult为true时，会在结构体字段标签中添加结果校验信息
//
// 示例：
//
//	data := map[string]interface{}{
//	    "name": "John",
//	    "age":  30,
//	    "hobbies": []string{"reading", "swimming"},
//	}
//	printJson(data, "", "", true, true, false)
func printJson(v interface{}, kong, stru string, isadd bool, showjson bool, showResult bool) string {
	switch vv := v.(type) {
	case string:
		if isadd {
			stru = fmt.Sprintf(stru, "string ")
		}
		if showjson {
			fmt.Print("\"" + strings.ReplaceAll(vv, "\"", "\\\"") + "\"")
		}
	case int:
		if isadd {
			stru = fmt.Sprintf(stru, "int ")
		}
		if showjson {

			fmt.Print(vv)
		}
	case float64:
		tmpv := strconv.FormatFloat(vv, 'f', -1, 64)
		if isadd {
			if strings.Contains(tmpv, ".") {
				stru = fmt.Sprintf(stru, "float64 ")
			} else {
				stru = fmt.Sprintf(stru, "int ")
			}
		}
		if showjson {

			fmt.Print(tmpv)
		}
	case bool:
		if isadd {
			stru = fmt.Sprintf(stru, "bool ")
		}
		if showjson {
			fmt.Print(vv)
		}
	case []interface{}:
		tmpst := "[]%s"
		kong += "  "

		if len(vv) == 0 {
			if showjson {
				fmt.Print("[]")
			}
			if isadd {
				stru = fmt.Sprintf(stru, "[]interface{} ")
			}
			return stru
		}
		if showjson {
			fmt.Print("[\n" + kong)
		}
		for i, u := range vv {
			if i == 0 {
				tmpst = printJson(u, kong, tmpst, true, showjson, showResult)
			} else {
				printJson(u, kong, tmpst, false, showjson, showResult)
			}
			if showjson {
				if i < len(vv)-1 {
					fmt.Print(",\n" + kong)
				}
			}
		}
		if tmpst == "[]%s" {
			tmpst = "[]interface{}"
		}
		if isadd {
			stru = fmt.Sprintf(stru, " "+tmpst+" ")
		}
		if showjson {
			fmt.Print("\n" + kong[0:len(kong)-2] + "]")
		}
	case map[string]interface{}:
		if len(vv) == 0 {
			if isadd {
				stru = fmt.Sprintf(stru, "map[string]interface{} ")
			}
			if showjson {
				fmt.Print("{}")
			}
			return stru
		}
		if showjson {
			fmt.Print("{")
		}
		kong += "  "
		frist := true
		tmpst := "struct{\n"
		//对 vv 的 key 进行排序
		keys := make([]string, 0, len(vv))
		for k := range vv {
			keys = append(keys, k)
		}
		sort.Strings(keys)
		for _, k := range keys {
			kk := vv[k]
			if isadd {
				km := strings.ToUpper(k[0:1]) + k[1:]
				if km == k {
					km = "T_" + km
				}
				switch vvd := kk.(type) {
				case string:
					vvd = strings.ReplaceAll(vvd, "\n", "\\n")
					vvd = strings.ReplaceAll(vvd, "\t", "\\t")
					vvd = strings.ReplaceAll(vvd, "\r", "\\r")
					if showResult {
						tmpst += kong + km + " %s `json:\"" + k + "\" result:\"eq:" + vvd + "\"`\n"
					} else {
						tmpst += kong + km + " %s `json:\"" + k + "\"`\n"
					}
				case int:
					if showResult {
						tmpst += kong + km + " %s `json:\"" + k + "\" result:\"eq:" + strconv.Itoa(vvd) + "\"`\n"
					} else {
						tmpst += kong + km + " %s `json:\"" + k + "\"`\n"
					}
				case float64:
					tmpv := strconv.FormatFloat(vvd, 'f', -1, 64)
					if strings.Contains(tmpv, ".") {
						if showResult {
							tmpst += kong + km + " %s `json:\"" + k + "\" result:\"eq:" + tmpv + "\"`\n"
						} else {
							tmpst += kong + km + " %s `json:\"" + k + "\"`\n"
						}
					} else {
						if showResult {
							tmpst += kong + km + " %s `json:\"" + k + "\" result:\"eq:" + strconv.Itoa(int(vvd)) + "\"`\n"
						} else {
							tmpst += kong + km + " %s `json:\"" + k + "\"`\n"
						}
					}
				case bool:
					if showResult {
						tmpst += kong + km + " %s `json:\"" + k + "\" result:\"eq:" + strconv.FormatBool(vvd) + "\"`\n"
					} else {
						tmpst += kong + km + " %s `json:\"" + k + "\"`\n"
					}
					// tmpst += kong + km + " %s `json:\"" + k + "\" result:\"eq:" + strconv.FormatBool(vvd) + "\"`\n"
				case []interface{}:
					if showResult {
						tmpst += kong + km + " %s `json:\"" + k + "\" list:\"gt:0\"`\n"
					} else {
						tmpst += kong + km + " %s `json:\"" + k + "\"`\n"
					}
				case map[string]interface{}:
					tmpst += kong + km + " %s `json:\"" + k + "\"`\n"
				case nil:
					if showResult {
						tmpst += kong + km + " %s `json:\"" + k + "\" result:\"ennill:true\"`\n"
					} else {
						tmpst += kong + km + " %s `json:\"" + k + "\"`\n"
					}
				case json.Number:
					if showResult {
						tmpst += kong + km + " %s `json:\"" + k + "\" result:\"eq:" + vvd.String() + "\"`\n"
					} else {
						tmpst += kong + km + " %s `json:\"" + k + "\"`\n"
					}
				case error:
					if showResult {
						tmpst += kong + km + " %s `json:\"" + k + "\" result:\"eq:" + vvd.Error() + "\"`\n"
					} else {
						tmpst += kong + km + " %s `json:\"" + k + "\"`\n"
					}

				}

			}
			if showjson {
				if frist {
					fmt.Print("\n" + kong + "  " + "\"" + k + "\"" + ": ")
					frist = false
				} else {
					fmt.Print(",\n" + kong + "  " + "\"" + k + "\"" + ": ")
				}
			}
			if isadd {
				tmpst = printJson(kk, kong+"  ", tmpst, true, showjson, showResult)
			} else {
				printJson(kk, kong+"  ", tmpst, false, showjson, showResult)
			}
		}
		kong2 := kong[0 : len(kong)-2]
		if isadd {
			tmpst += kong2 + "}"
			stru = fmt.Sprintf(stru, ""+tmpst+" ")
		}
		if showjson {
			fmt.Print("\n" + kong2 + "}")
		}
	case nil:
		if isadd {
			stru = fmt.Sprintf(stru, "buzhidao!! ")
		}
		if showjson {
			fmt.Print("null")
		}
	case error:
		if showjson {
			fmt.Print(v)
		}
	case int64:
		if isadd {
			stru = fmt.Sprintf(stru, "int64 ")
		}
		if showjson {
			fmt.Print(vv)
		}
	case json.Number:
		if isadd {
			stru = fmt.Sprintf(stru, "int ")
		}
		if showjson {
			fmt.Print(vv)
		}

	default:
		if showjson {
			fmt.Println(v, "格式错误")
			typeOfA := reflect.TypeOf(vv)
			fmt.Println(typeOfA, typeOfA.Name(), "--", typeOfA.Kind())
		}
	}
	return stru
}
